use base::client;
use lazy_static::lazy_static;
use optdb::{do_cmd, init_dir, Lock, SvCache};
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::Mutex;
use tracing::{instrument, warn};
use tracing_subscriber::prelude::*;
use warp::{hyper::body::Bytes, Filter};

#[instrument(skip_all, name = "main")]
#[tokio::main]
async fn main() {
    base::trace_warn!();

    init_dir();

    lazy_static! {
        static ref LOCK: Lock = Arc::new(Mutex::new(()));
        static ref CLIENT: client::Client = client::Client::new();
        static ref CACHE: SvCache = SvCache::builder()
            .max_capacity(1_0000)
            .time_to_idle(Duration::from_secs(24 * 60 * 60 * 15)) // 15 days
            .build();
    }

    let md = "optdb";
    let body = base::body!();

    let post_three = warp::path(md)
        .and(warp::post())
        .and(warp::path::param())
        .and(warp::path::param())
        .and(body)
        .and_then(move |model: String, cmd: String, data: Bytes| async {
            let lock = Arc::clone(&LOCK);
            do_cmd(data, model, cmd, CACHE.clone(), lock, &CLIENT).await
        });

    let post = post_three.with(base::cors!());

    let get = warp::get().map(move || format!("\nserve: {}\n\n", md));
    let opt = base::opt!();

    let route = get.or(opt).or(post);

    warn!("listening on 0.0.0.0:9990");

    warp::serve(route).run(([0, 0, 0, 0], 9990)).await;
}
